/*
 * Servidor.cpp
 *
 *  Created on: 28/05/2012
 *      Author: sebastian
 */

#include "Servidor.h"
#include "Hilo_Enviador.h"
#include "Hilo_Recibidor.h"
#include "Worker.h"

Servidor::Servidor(std::string serv_port, Validador& val) : s_socket(serv_port.c_str()), validator(val), datos(val), agent_handler(Auxiliar::itos(AGENT_PORT), *this) {
	consultas = new Cola<Consulta*>;
	std::string linea("datos.txt");
	datos.cargar(linea);
	//  respuestas = new Cola<Respuesta*>;
	for(int i = 0; i < MAX_WORKERS; ++i) {
		Worker* w = new Worker(*consultas, respuestas, datos, *this);
		workers.push_back(w);
	}
	enviador = new Hilo_Enviador(*this);
}



Servidor::~Servidor() {
}

void Servidor::run() {
	s_socket.enlazar();
	s_socket.escuchar();
	agent_handler.start();	
	for(int i = 0; i < MAX_WORKERS; ++i) {
		workers[i]->start();
	}
	enviador->start();
	while(isRunning()) {
		int client_fd = s_socket.aceptar();
		if(client_fd > 0) {
			Socket* s = new Socket(Auxiliar::itos(SERVER_PORT).c_str(), client_fd);
			Hilo_Recibidor* recibidor = new Hilo_Recibidor(*this, s);
			recibidores.push_back(recibidor);
			enviador->agregarSocket(s);
			if(!recibidores[recibidores.size() - 1]->isRunning())
				recibidores[recibidores.size() - 1]->start();
		}
	}
	cerrarServidor();


}

void Servidor::cerrarSocket() {
	s_socket.cerrar();
}

void Servidor::cerrarServidor() {
	std::vector<Hilo_Recibidor*>::iterator it_recibidores;
	for(it_recibidores = recibidores.begin(); it_recibidores != recibidores.end(); ++it_recibidores) {
		Hilo_Recibidor* hilo = *it_recibidores;
		hilo->stop();
		hilo->cerrarSocket();
	}
	for(it_recibidores = recibidores.begin(); it_recibidores != recibidores.end(); ++it_recibidores) {
		Hilo_Recibidor* hilo = *it_recibidores;
		hilo->join();
		delete hilo;
	}
	agent_handler.stop();
	agent_handler.cerrar();
	agent_handler.join();
	respuestas.broadcast();
	enviador->stop();
	enviador->join();
	std::vector<Worker*>::iterator it_workers;
	for(it_workers = workers.begin(); it_workers != workers.end(); ++it_workers) {
			Worker* worker = *it_workers;
			worker->stop();
	}
	consultas->broadcast();
	for(it_workers = workers.begin(); it_workers != workers.end();) {
		Worker* worker = *it_workers;
		worker->join();
		it_workers = workers.erase(it_workers);
		delete worker;
	}
	delete consultas;
	// borrar cada consulta y respuesta?
	delete enviador;
}

Cola<Consulta*>* Servidor::getColaConsultas() {
	return consultas;
}

/*Cola<Respuesta*> Servidor::getColaRespuestas() {
	return respuestas;
}*/

void Servidor::pushRespuesta(Respuesta* r) {
	respuestas.push(r);
}

void Servidor::pushConsulta(Consulta* c) {
	consultas->push(c);
}

Respuesta* Servidor::popRespuesta() {
	Respuesta* res;
	try {
		res = respuestas.pop();
	} catch(int i) {		//  hacer una excepcion aparte
		return NULL;
	}
	return res;
}

Consulta* Servidor::popConsulta() {
	Consulta* cons;
	try {
		cons = consultas->pop();
	} catch(int i) {		//  hacer una excepcion aparte
		return NULL;
	}
	return cons;
}

void Servidor::guardar(std::string& linea) {
	this->datos.Agregar(linea);

}

std::string Servidor::getNombreAtributo(int pos, int nTabla) {
	return validator.getNombreAtributo(pos, nTabla);
}
